﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using MovieBuddy.Dialogs;
using MovieBuddy.Events;
using MovieBuddy.Views.ItemListView;
using MovieModel.Model;
using MovieModel.Model.Common;
using MovieModel.Search;

namespace MovieBuddy.Views.TriViews
{
    /// <summary>
    /// Interaction logic for TriView.xaml
    /// </summary>
    public abstract partial class TriView
    {
        protected UserControl LeftControl;

        protected TriView(string typeName, UserControl leftControl, Manager manager)
        {
            LeftControl = leftControl;
            InitializeComponent();
            typeLabel.Content = typeName;
            listPanel.Children.Add(leftControl);
            movieView.Manager = manager;
            editButton.IsEnabled = false;
        }

        protected abstract void ClearSelectionClicked(object sender, RoutedEventArgs e);

        protected abstract void EditButtonClick(object sender, RoutedEventArgs e);
    }

    public abstract class AbstractTriView<T> : TriView, IMovieBuddyViewController<AbstractTriView<T>>, ISearchAcceptor where T : MovieItem<T>, new()
    {
        protected readonly ItemList<T> ItemList;
        protected readonly Manager Manager;

        protected AbstractTriView(string typeName, Manager manager) :
            base(typeName, new ItemList<T>(), manager)
        {
            Manager = manager;
            ItemList = (ItemList<T>)LeftControl;
            ItemList.SelectionChanged += (s, e) => CurrentSearch = currentSearch;
            ItemList.SelectionChanged += (s, e) => editButton.IsEnabled = ItemList.SelectedItems.Length == 1;
        }

        protected abstract SearchQuery ApplySelectionFilter(SearchQuery query);

        protected abstract IEnumerable<T> AllItems
        {
            get;
        }

        protected override void ClearSelectionClicked(object sender, RoutedEventArgs e)
        {
            ItemList.ClearSelection();
        }

        protected abstract IEnumerable<T> ItemsInMovies(IEnumerable<Movie> movies); 

        private SearchQuery currentSearch;
        public SearchQuery CurrentSearch
        {
            get { return currentSearch; }
            set
            {
                if (Manager == null) return;

                var appliedSearch = ApplySelectionFilter(value);
                movieView.CurrentSearch = appliedSearch;

                if (currentSearch != value)
                {
                    currentSearch = value;
                    if (currentSearch.IsBlank)
                    {
                        ItemList.Items = AllItems;
                    }
                    else
                    {
                        ItemList.Items =
                            ItemsInMovies(Manager.Movies.Values.Where(m => value == null || m.Matches(currentSearch)));
                    }
                }
            }
        }

        public void InvokeSearchChanged(SearchEventArgs e)
        {
            CurrentSearch = e.NewSearchValue;
        }

        public AbstractTriView<T> Control
        {
            get { return this; }
        }

        public ISearchAcceptor SearchAcceptor
        {
            get { return this; }
        }
    }

    public class PeopleView : AbstractTriView<Person>
    {
        public PeopleView(Manager manager) : base("People", manager)
        {
            manager.PersonAdded += (s, e) => ItemList.AddItem(e.AddedItem);
        }


        protected override SearchQuery ApplySelectionFilter(SearchQuery query)
        {
            var people = ItemList.SelectedItems.Select(i => i.Item).Cast<Person>().ToList();
            if (!people.Any()) people = null;
            return new SearchQuery
            {
                Free = query.Free,
                People = people
            };
        }

        protected override IEnumerable<Person> AllItems
        {
            get { return Manager.People.Values; }
        }

        protected override IEnumerable<Person> ItemsInMovies(IEnumerable<Movie> movies)
        {
            var people = new HashSet<Person>();
            foreach (var movie in movies)
            {
                foreach (var person in movie.People.Select(mp => mp.Person))
                {
                    if (!people.Contains(person))
                    {
                        people.Add(person);
                        yield return person;
                    }
                }
            }
        }

        protected override void EditButtonClick(object sender, RoutedEventArgs e)
        {
            var person = ItemList.SelectedItems.First().Item;
            var dialog = new EditImageMovieItemDialog("person", person.Name, person.ImageLocation);
            dialog.SaveClicked += (s, e2) => DialogSaveClicked(person, e2);
            dialog.ShowDialog();
        }

        void DialogSaveClicked(Person person, EditImageMovieItemDialog.SaveButtonClickedEventArgs e)
        {
            string thumbnail = person.ThumbnailLocation;
            string image = person.ImageLocation;
            if (e.Image != person.ImageLocation)
            {
                var thumb = new Manager.ThumbnailRequest(null, 61);
                image = Manager.ImportFile(new Uri(e.Image), thumb).FullName;
                thumbnail = thumb.File.FullName;
            }
            person.Update(e.Name, image, thumbnail);
        }
    }

    public class TagView : AbstractTriView<Tag>
    {
        public TagView(Manager manager) : base("Tags", manager)
        {
            manager.TagAdded += (s, e) => Dispatcher.Invoke(() => ItemList.AddItem(e.AddedItem));
        }


        protected override SearchQuery ApplySelectionFilter(SearchQuery query)
        {
            var tags = ItemList.SelectedItems.Select(i => i.Item).Cast<Tag>().ToList();
            if (!tags.Any()) tags = null;
            return new SearchQuery
            {
                Free = query.Free,
                Tags = tags
            };
        }

        protected override IEnumerable<Tag> AllItems
        {
            get { return Manager.Tags.Values; }
        }

        protected override IEnumerable<Tag> ItemsInMovies(IEnumerable<Movie> movies)
        {
            var tags = new HashSet<Tag>();
            foreach (var movie in movies)
            {
                foreach (var tag in movie.Tags)
                {
                    if (!tags.Contains(tag))
                    {
                        tags.Add(tag);
                        yield return tag;
                    }
                }
            }
        }

        protected override void EditButtonClick(object sender, RoutedEventArgs e)
        {
            var tag = ItemList.SelectedItems.First().Item;
            var dialog = new EditImageMovieItemDialog("tag", tag.Name, tag.ImageLocation);
            dialog.SaveClicked += (s, e2) => DialogSaveClicked(tag, e2);
            dialog.ShowDialog();
        }

        void DialogSaveClicked(Tag tag, EditImageMovieItemDialog.SaveButtonClickedEventArgs e)
        {
            string thumbnail = tag.ThumbnailLocation;
            string image = tag.ImageLocation;
            if (string.IsNullOrEmpty(e.Image))
            {
                thumbnail = null;
                image = null;
            }
            else if (e.Image != tag.ImageLocation)
            {
                var thumb = new Manager.ThumbnailRequest(null, 61);
                image = Manager.ImportFile(new Uri(e.Image), thumb).FullName;
                thumbnail = thumb.File.FullName;
            }
            tag.Update(e.Name, image, thumbnail);
        }
    }
}
